package org.pentaho.huaweicloud.obs;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.pentaho.di.connections.vfs.VFSDetailsComposite;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.StringUtil;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.variables.Variables;
import org.pentaho.di.core.vfs.connections.ui.dialog.VFSDetailsCompositeHelper;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.widget.*;

import java.util.Arrays;
import java.util.HashSet;
import java.util.stream.IntStream;

public class OBSDetailComposite implements VFSDetailsComposite {
    private static final Class<?> PKG = OBSDetailComposite.class;
    private final Composite wComposite; //The content for the parentComposite
    private final OBSDetails details;
    private final VFSDetailsCompositeHelper helper;
    private final PropsUI props;

    private static final String[] OBS_CONNECTION_TYPE_CHOICES = new String[] { "HuaweiCloud" };
    private static final String[] AUTH_TYPE_CHOICES = new String[] { "Access Key/Secret Key" };
    private static final int TEXT_VAR_FLAGS = SWT.SINGLE | SWT.LEFT | SWT.BORDER;
    private final String[] regionChoices;
    private boolean initializingUiForFirstTime = true;
    private CCombo wOBSConnectionType;
    private CCombo wAuthType;

    private Composite wBottomHalf;
    private Composite wWidgetHolder;

    private ComboVar wRegion;
    private PasswordVisibleTextVar wAccessKey;
    private PasswordVisibleTextVar wSecretKey;

    private VariableSpace variableSpace = Variables.getADefaultVariableSpace();
    private HashSet<Control> skipControls = new HashSet<>();

    public OBSDetailComposite( Composite composite, OBSDetails details, PropsUI props ) {
        helper = new VFSDetailsCompositeHelper( PKG, props );
        this.props = props;
        this.wComposite = composite;
        this.details = details;
        // endpoint选择
        regionChoices = details.getRegions().toArray( new String[ 0 ] );
    }

    public Object open() {
        FormLayout genLayout = new FormLayout();
        genLayout.marginWidth = Const.FORM_MARGIN;
        genLayout.marginHeight = Const.FORM_MARGIN;
        wComposite.setLayout( genLayout );

        //Title
        Label wlTitle = helper.createTitleLabel( wComposite, "ConnectionDialog.obs.Details.Title", skipControls );

        // OBS Connection Type
        Label wlConnectionType = createLabel( "ConnectionDialog.obs.ConnectionType.Label", wlTitle, wComposite );
        wOBSConnectionType = createCCombo( wlConnectionType, 200, wComposite );
        wOBSConnectionType.setItems( OBS_CONNECTION_TYPE_CHOICES );
        wOBSConnectionType.select( Integer.parseInt( Const.NVL( details.getConnectionType(), "0" ) ) );


        // This composite will fill dynamically based on connection type and auth type
        wBottomHalf = new Composite( wComposite, SWT.NONE );
        FormLayout bottomHalfLayout = new FormLayout();
        wBottomHalf.setLayout( bottomHalfLayout );

        FormData wfdBottomHalf = new FormData();
        wfdBottomHalf.top = new FormAttachment( wOBSConnectionType, 0 );
        wfdBottomHalf.left = new FormAttachment( 0, 0 );
        wfdBottomHalf.right = new FormAttachment( 100, 0 );
        wBottomHalf.setLayoutData( wfdBottomHalf );
        props.setLook( wBottomHalf );

        //This composite holds controls that are not currently in use.  No layout needed here
        wWidgetHolder = new Composite( wComposite, SWT.NONE );
        wWidgetHolder.setVisible( false );

        wAuthType = createStandbyCombo();
        wAuthType.setItems( AUTH_TYPE_CHOICES );
        wAuthType.select( Integer.parseInt( Const.NVL( details.getAuthType(), "0" ) ) );
        wRegion = createStandbyComboVar();
        wRegion.setItems( regionChoices );
        wRegion.select( 0 );
        wAccessKey = createStandbyPasswordVisibleTextVar();
        wSecretKey = createStandbyPasswordVisibleTextVar();
        skipControls.add( wBottomHalf );
        skipControls.add( wWidgetHolder );

        setupBottomHalf();

        // Set the data
        populateWidgets();

        //add Listeners
        for ( CCombo cCombo : Arrays.asList( wOBSConnectionType, wAuthType ) ) {
            cCombo.addSelectionListener( new SelectionAdapter() {
                @Override public void widgetSelected( SelectionEvent selectionEvent ) {
                    setupBottomHalf();
                }
            } );
        }
        wRegion.addSelectionListener( new SelectionAdapter() {
            @Override public void widgetSelected( SelectionEvent selectionEvent ) {
                details.setEndpoint( wRegion.getText() );
            }
        } );
        wRegion.addModifyListener( modifyEvent -> details.setEndpoint( wRegion.getText() ) );
        wAccessKey.addModifyListener( modifyEvent -> details.setAccessKey( wAccessKey.getText() ) );
        wSecretKey.addModifyListener( modifyEvent -> details.setSecretKey( wSecretKey.getText() ) );

        helper.setupCompositeResizeListener( wComposite );
        initializingUiForFirstTime = false;
        return wComposite;
    }

    private void setupBottomHalf() {
        setupBottomHalf( computeComboIndex( wOBSConnectionType.getText(), OBS_CONNECTION_TYPE_CHOICES, 0 ),
                computeComboIndex( wAuthType.getText(), AUTH_TYPE_CHOICES, 0 ) );
    }

    private void setupBottomHalf( int obsConnectionType, int authType ) {
        if ( initializingUiForFirstTime || obsConnectionType != stringToInteger( details.getConnectionType() ) ) {
            details.setConnectionType( String.valueOf( obsConnectionType ) );
        }
        if ( initializingUiForFirstTime || authType != stringToInteger( details.getAuthType() ) ) {
            details.setAuthType( String.valueOf( authType ) );
        }

        for ( Control c : wBottomHalf.getChildren() ) {
            if ( c instanceof Label ) {
                c.dispose(); //Dispose any labels
            } else {
                c.setParent( wWidgetHolder ); //Other widgets go back to the wWidgetHolder (they hold the current value)
            }
        }

        switch( obsConnectionType * 10 + authType ) {
            case 0: // HuaweiCloud with Access Key
                moveWidgetToBottomHalf( wAuthType, "ConnectionDialog.obs.AuthType.Label", null, 200 );
                moveWidgetToBottomHalf( wRegion, "ConnectionDialog.obs.Endpoint.Label", wAuthType, 200 );
                moveWidgetToBottomHalf( wAccessKey, "ConnectionDialog.obs.AccessKey.Label", wRegion );
                moveWidgetToBottomHalf( wSecretKey, "ConnectionDialog.obs.SecretKey.Label", wAccessKey );
                break;
            default:

        }

        wBottomHalf.layout();
        wComposite.pack();
        helper.updateScrollableRegion( wComposite );
    }

    private void populateWidgets() {
        wOBSConnectionType.select( stringToInteger( details.getConnectionType() ) );
        wAuthType.select( stringToInteger( details.getAuthType() ) );
        wAccessKey.setText( Const.NVL( details.getAccessKey(), "" ) );
        wSecretKey.setText( Const.NVL( details.getSecretKey(), "" ) );
        int regionIndex = computeComboIndex( Const.NVL( details.getEndpoint(), regionChoices[ 0 ] ), regionChoices, -1 );
        if ( regionIndex != -1 ) {
            wRegion.select( regionIndex );
        } else {
            wRegion.setText( details.getEndpoint() );
        }
    }

    private Label createLabel( String key, Control topWidget, Composite composite ) {
        return helper.createLabel( composite, SWT.LEFT | SWT.WRAP, key, topWidget );
    }

    private PasswordVisibleTextVar createStandbyPasswordVisibleTextVar() {
        return new PasswordVisibleTextVar( variableSpace, wWidgetHolder, SWT.LEFT | SWT.BORDER );
    }

    private CCombo createCCombo( Control topWidget, int width, Composite composite ) {
        return helper.createCCombo( composite, TEXT_VAR_FLAGS, topWidget, width );
    }

    private CCombo createStandbyCombo() {
        return new CCombo( wWidgetHolder, TEXT_VAR_FLAGS );
    }

    private ComboVar createStandbyComboVar() {
        return new ComboVar( variableSpace, wWidgetHolder, TEXT_VAR_FLAGS );
    }

    private void moveWidgetToBottomHalf( Control targetWidget, String labelKey, Control topWidget ) {
        moveWidgetToBottomHalf( targetWidget, labelKey, topWidget, 0 );
    }

    private void moveWidgetToBottomHalf( Control targetWidget, String labelKey, Control topWidget, int width ) {
        Label lbl = createLabel( labelKey, topWidget, wBottomHalf );
        targetWidget.setParent( wBottomHalf );
        props.setLook( targetWidget );
        targetWidget.setLayoutData( helper.getFormDataField( lbl, width ) );
    }

    @Override
    public void close() {
        wComposite.dispose();
        if ( wBottomHalf != null ) {
            wBottomHalf.dispose();
        }

    }

    private int stringToInteger( String value ) {
        return Integer.parseInt( Const.NVL( value, "0" ) );
    }

    private int computeComboIndex( String targetValue, String[] choices, int notFoundReturnValue ) {
        return IntStream.range( 0, choices.length )
                .filter( i -> choices[ i ].equals( targetValue ) )
                .findFirst().orElse( notFoundReturnValue );
    }

    public String validate() {
        int regionIndex = computeComboIndex( Const.NVL( details.getEndpoint(), regionChoices[ 0 ] ), regionChoices, -1 );
        if ( regionIndex == -1 && !StringUtil.isVariable( details.getEndpoint() ) ) {
            return BaseMessages.getString( PKG, "ConnectionDialog.obs.Validate.badRegionText" );
        }
        return null;
    }

}

